package com.file.parser;

import com.file.bo.Gdbdc;
import com.file.bo.ResponseData;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Slf4j
public class GdbdcPdfParser extends BasePdfParser {

    public ResponseData<String> parseGdbdcPdfToJson(String daId, String filePath) {
        log.info("parseGdbdcPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            if (StringUtils.lowerCase(filePath).endsWith("ofd")) {
                Gdbdc gdbdc = parseOfdText(filePath);
                json = JsonUtils.convertObjectToJson(gdbdc);
            } else {
                Gdbdc gdbdc = parsePdfText(filePath);
                json = JsonUtils.convertObjectToJson(gdbdc);
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuangdongSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseGuangdongSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private Gdbdc parseOfdText(String filePath) throws Exception {
        Gdbdc gdbdc = new Gdbdc();
        try {
            byte[] ofdBytes = Files.readAllBytes(Paths.get(filePath));
            // 解压OFD文件到内存
            byte[] docMetaBytes = unzipToMemory(ofdBytes, "OFD.xml");
            String xmlContent = new String(docMetaBytes, StandardCharsets.UTF_8);
            // 解析
            Document docDocument = parseXml(new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8)));
            Element rootElement = docDocument.getRootElement();
            Element customDatas = rootElement.element("DocBody").element("DocInfo").element("CustomDatas");
            for (Element element : customDatas.elements()) {
                String content = element.getText();
                String name = element.attribute(0).getValue();
                if (name.equalsIgnoreCase("ZZBFRQ")) {
                    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    LocalDate date = LocalDate.parse(content, inputFormatter);
                    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
                    String formattedDateString = date.format(outputFormatter);
                    gdbdc.setIssuanceTime(formattedDateString);
                }
                if (name.equalsIgnoreCase("ZZBFJG")) {
                    gdbdc.setIssuer(content);
                }
                if (name.equalsIgnoreCase("ZZBH")) {
                    gdbdc.setCertNo(content);
                }
                if (name.equalsIgnoreCase("CZZT")) {
                    gdbdc.setHolder(content);
                }
                if (name.equalsIgnoreCase("KZ_GYQK")) {
                    gdbdc.setCoOwnership(content);
                }
                if (name.equalsIgnoreCase("KZ_ZL")) {
                    gdbdc.setSito(content);
                }
                if (name.equalsIgnoreCase("KZ_BDCDYH")) {
                    gdbdc.setUnitNumber(content);
                }
                if (name.equalsIgnoreCase("KZ_QLLX")) {
                    gdbdc.setRightsType(content);
                }
                if (name.equalsIgnoreCase("KZ_QLXZ")) {
                    gdbdc.setRightsNature(content);
                }
                if (name.equalsIgnoreCase("KZ_YT")) {
                    gdbdc.setPurpose(content);
                }
                if (name.equalsIgnoreCase("KZ_MJ")) {
                    gdbdc.setArea(content);
                }
                if (name.equalsIgnoreCase("KZ_SYQX")) {
                    gdbdc.setPeriod(content);
                }
                if (name.equalsIgnoreCase("KZ_QLQTZK")) {
                    gdbdc.setRightsOtherConditions(content);
                }
                if (name.equalsIgnoreCase("KZ_FJ")) {
                    gdbdc.setAddendum(content);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return gdbdc;
    }

    private static Document parseXml(InputStream xmlStream) throws Exception {
        SAXReader reader = new SAXReader();
        reader.setEncoding("UTF-8");
        return reader.read(xmlStream);
    }

    private static byte[] unzipToMemory(byte[] zipBytes, String entryName) throws Exception {
        InputStream inputStream = new ByteArrayInputStream(zipBytes);
        ZipInputStream zipIn = new ZipInputStream(inputStream);
        ZipEntry entry = zipIn.getNextEntry();

        while (entry != null) {
            if (entry.getName().equals(entryName)) {
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = zipIn.read(buffer)) > 0) {
                    byteArrayOutputStream.write(buffer, 0, len);
                }
                zipIn.closeEntry();
                zipIn.close();
                return byteArrayOutputStream.toByteArray();
            }
            zipIn.closeEntry();
            entry = zipIn.getNextEntry();
        }
        zipIn.close();
        throw new Exception("Entry not found: " + entryName);
    }

    private Gdbdc parsePdfText(String filePath) {
        Gdbdc gdbdc = new Gdbdc();
        String pdfText = getPdfTextByStripper(filePath);
        String separatorLine = System.getProperty("line.separator", "\n");
        String[] lines = pdfText.split(separatorLine);
        // 处理发证日期
        // 处理全角空格
        String[] parts = lines[0].replace('\u3000', ' ').trim().split("\\s+");
        if (parts.length == 3) {
            gdbdc.setIssuanceTime(String.format("%s年%s月%s日", parts[0], parts[1], parts[2]));
        } else {
            gdbdc.setIssuanceTime(lines[0]);
        }
        // 处理发证方
        gdbdc.setIssuer(lines[1].replace("此件由", "").replace("提供", ""));
        // 处理权证号
        parts = lines[2].trim().split("[\\s　]+"); //NOSONAR
        if (parts.length == 4) {
            gdbdc.setCertNo(String.format("%s(%s)%s不动产权第%s号", parts[0], parts[1], parts[2], parts[3]));
        } else if (parts.length == 3) {
            // 特殊格式，编号和年份混杂一起，提取编号
            Pattern numPattern = Pattern.compile("\\d+");
            Matcher numMatcher = numPattern.matcher(parts[2]);
            String certIdNum = StringUtils.EMPTY;
            while (numMatcher.find()) {
                certIdNum = numMatcher.group();
            }
            String certCity = parts[2].replaceAll("\\d+", "");
            gdbdc.setCertNo(String.format("%s(%s)%s不动产权第%s号", parts[0], parts[1], certCity, certIdNum));
        } else {
            gdbdc.setCertNo(lines[2]);
        }
        gdbdc.setHolder(lines[3]);
        gdbdc.setCoOwnership(lines[4]);
        // 处理坐落多于一行的情况，假设坐落不超过三行
        int lineNum = 5;
        String sitoValue = "";
        // 如果这一行是以数字开头，那就不再是坐落了
        for (; lineNum < 8; lineNum++) {
            if (lines[lineNum].length() > 0 && !Character.isDigit(lines[lineNum].charAt(0))) {
                sitoValue += lines[lineNum];
            } else {
                break;
            }
        }
        gdbdc.setSito(sitoValue);

        gdbdc.setUnitNumber(lines[lineNum]);
        lineNum++;

        gdbdc.setRightsType(lines[lineNum]);
        lineNum++;

        gdbdc.setRightsNature(lines[lineNum]);
        lineNum++;

        gdbdc.setPurpose(lines[lineNum]);
        lineNum++;

        gdbdc.setArea(lines[lineNum]);
        lineNum++;

        // 处理使用期限多于一行的情况
        String periodValue = "";
        for (; ; lineNum++) {
            String str = lines[lineNum];
            if (str.length() > 0) {
                // 两种顿号满足一种，说明到了期限行
                boolean stopCondition = str.trim().matches("^\\d+\\s*、.*");
                boolean stopCondition2 = str.trim().matches("^\\d+\\.\\s*.*");
                if (stopCondition || stopCondition2) {
                    break;
                } else {
                    periodValue += str;
                }
            }
        }
        gdbdc.setPeriod(periodValue);
        // 判断阿拉伯数字和英文句点构成的权利其他状况
        String rightsOtherConditions = Strings.EMPTY;
        Pattern pattern = Pattern.compile("\\b(\\d+)\\.");
        Pattern pattern2 = Pattern.compile("\\b(\\d+)、");
        int lastIndex = 0;
        for (; lineNum < 50; lineNum++) {
            Matcher matcher = pattern.matcher(lines[lineNum]);
            Matcher matcher2 = pattern2.matcher(lines[lineNum]);
            boolean found = false;
            while (matcher.find()) {
                found = true;
                String number = matcher.group(1);
                lastIndex = Integer.parseInt(number);
//                System.out.println("index: " + number);
            }
            while (matcher2.find()) {
                found = true;
                String number = matcher2.group(1);
                lastIndex = Integer.parseInt(number);
//                System.out.println("index: " + number);
            }

            if (found || lastIndex < 5) {
                rightsOtherConditions += lines[lineNum].replace("\n", "").replace("\r", "").trim();
            }
            if (lastIndex == 5) {
                // 对存在共有的情况：读本行和下一行，如果存在“无”，则卡到无这一行。如果没有无，则无脑多读一行。
                String strThis = lines[lineNum];
                String strNext = lines[lineNum + 1];
                if (strThis.contains("无")) {
                    break;
                } else {
                    rightsOtherConditions += strNext;
                }
                break;
            }
        }
        gdbdc.setRightsOtherConditions(rightsOtherConditions);
        // 判断附记
        lineNum++;
        if (rightsOtherConditions.contains(lines[lineNum])) {
            lineNum++;
        }
        String addendum = Strings.EMPTY;
        for (; lineNum < 100; lineNum++) {
            if (lines[lineNum].contains("此")) {
                break;
            }
            addendum += lines[lineNum].replace("\n", "").replace("\r", "").trim();
        }
        gdbdc.setAddendum(addendum);
        return gdbdc;
    }

    public static void main(String[] args) {
        String filePath = "D:\\data\\file\\gdbdc\\example-01.pdf";
        GdbdcPdfParser gdbdcPdfParser = new GdbdcPdfParser();
        ResponseData<String> responseData = gdbdcPdfParser.parseGdbdcPdfToJson("", filePath);
        System.out.println(responseData.getData());
    }
}
